package com.example.helloworld;


import com.alibaba.cloud.ai.dashscope.agent.DashScopeAgentOptions;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;

@RestController
@RequestMapping("/helloworld")
public class HellowordController {

    // 默认的系统提示词（system prompt），用于设定 AI 助手的角色和行为准则
    private static final String DEFAULT_PROMPT = "you are a helpful assistant";

    // 声明一个不可变的 ChatClient 实例，用于与大模型（如通义千问）进行对话
    private final ChatClient dashScopeChatClient;

    /**
     * 构造函数：通过 Spring 容器注入 ChatClient.Builder，
     * 并在此完成对 DashScope 聊天客户端的个性化配置与构建。
     *
     * @param chatClientBuilder 由 Spring 提供的预配置好的 ChatClient 构建器（通常在 @Configuration 类中定义）
     */
    public HellowordController(ChatClient.Builder chatClientBuilder) {
        this.dashScopeChatClient = chatClientBuilder
                // 设置默认的系统消息（system prompt），所有对话都会隐式包含此上下文
                .defaultSystem(DEFAULT_PROMPT)

                // 添加一个“聊天记忆”顾问（Advisor）：
                // 使用滑动窗口策略（MessageWindowChatMemory）自动管理对话历史，
                // 确保模型能“记住”最近的几轮对话，实现上下文连贯的多轮交互
                .defaultAdvisors(
                        MessageChatMemoryAdvisor.builder(
                                MessageWindowChatMemory.builder()
                                        .build() // 可进一步配置窗口大小，如 .maxMessages(10)
                        ).build()
                )

                // 添加一个“简单日志”顾问（Advisor）：
                // 在每次调用模型前后自动打印请求与响应内容，便于调试和观察
                .defaultAdvisors(new SimpleLoggerAdvisor())

                // 配置模型生成时的参数选项（针对 DashScope 平台）
                .defaultOptions(
                        DashScopeChatOptions.builder()
                                .withTopP(0.9) // 启用 nucleus sampling，控制生成多样性（值越小越确定，越大越随机）
                                .build()
                )

                // 最终构建出一个可直接使用的 ChatClient 实例
                .build();
    }


    /**
     * 【简单同步调用】
     * 发起一次单轮、非流式、无上下文记忆的 AI 对话。
     * 适用于快速测试或一次性问答场景。
     *
     * @param query 用户输入的问题（默认为 "Who are you?"）
     * @return 模型的完整回复文本
     */
    @GetMapping("/simple/chat")
    public String simpleChat(
            @RequestParam(value = "query", defaultValue = "Who are you?") String query
    ) {
        // .call() 表示同步阻塞调用，等待完整响应后返回
        return dashScopeChatClient.prompt(query).call().content();
    }

    /**
     * 【流式响应调用】
     * 以 Server-Sent Events (SSE) 形式流式返回模型生成的内容，
     * 实现“打字机”效果，提升用户体验。
     * 注意：此方法仍为单轮对话，不保留历史上下文。
     *
     * @param query 用户输入的问题
     * @param response HttpServletResponse，用于设置字符编码（确保中文不乱码）
     * @return Flux<String> 流式响应，Spring Boot 会自动转为 text/event-stream
     */
    @GetMapping(value = "/stream/chat", produces = "text/event-stream;charset=UTF-8")
    public Flux<String> streamChat(
            @RequestParam(value = "query", defaultValue = "Who are you?") String query,
            HttpServletResponse response
    ) {
        // 显式设置 UTF-8 编码（虽然 produces 已声明，双重保险）
        response.setCharacterEncoding("UTF-8");
        // .stream() 表示启用流式生成，逐 token 返回
        return dashScopeChatClient.prompt(query).stream().content();
    }

    /**
     * 【带会话 ID 的多轮流式对话】
     * 支持真正的多轮上下文对话：通过 conversationId 关联同一用户的多次交互。
     * 每次调用时，Advisor 会自动加载该会话的历史消息作为上下文发送给模型，
     * 并在响应后将新消息存入内存，实现“记忆”功能。
     *
     * ⚠️ 注意：默认使用内存存储（In-Memory），应用重启后会话丢失，不适用于生产多实例环境。
     *
     * @param response HttpServletResponse，设置 UTF-8 编码
     * @param conversationId 会话唯一标识（如用户 ID 或会话 UUID）
     * @param query 当前轮次的用户输入
     * @return 流式返回的模型回复
     */
    @GetMapping(value = "/advisor/chat/{conversationId}", produces = "text/event-stream;charset=UTF-8")
    public Flux<String> advisorChat(
            HttpServletResponse response,
            @PathVariable String conversationId,
            @RequestParam String query
    ) {
        response.setCharacterEncoding("UTF-8");

        return this.dashScopeChatClient.prompt(query)
                // 动态传入会话 ID，使 MessageChatMemoryAdvisor 能按 ID 管理上下文
                .advisors(advisorSpec ->
                        advisorSpec.param(ChatMemory.CONVERSATION_ID, conversationId)
                )
                .stream()      // 启用流式响应
                .content();    // 仅提取回复文本内容
    }
}
